home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / mail / transpor / ifmail23.z / ifmail23 / ifmail / ifcico / zmsend.c < prev   
Encoding:
C/C++ Source or Header  |  1994-05-10  |  12.7 KB  |  657 lines

  1. #include <unistd.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <time.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include "ttyio.h"
  11. #include "xutil.h"
  12. #include "lutil.h"
  13. #include "session.h"
  14. #include "zmodem.h"
  15. #include "emsi.h"
  16.  
  17. static int initsend(void);
  18. static int sendfile(char*,char*);
  19. static int finsend(void);
  20.  
  21. static int getzrxinit(void);
  22. static int sendzsinit(void);
  23. static int zfilbuf(void);
  24. static int zsendfile(char*,int);
  25. static int zsendfdata(void);
  26. static int getinsync(int);
  27.  
  28. static FILE *in;
  29. static int Test=0;
  30. static int Eofseen;
  31. static int Rxflags;
  32. static int Usevhdrs;
  33. static int Wantfcs32=TRUE;
  34. static int Rxbuflen;
  35. static int Txwindow;
  36. static int Tframlen;
  37. static int Txwcnt;
  38. static int blklen;
  39. static int blkopt;
  40. static int Txwspac;
  41. static int errors;
  42. static int Lastsync;
  43. static int bytcnt;
  44. static int Lrxpos=0;
  45. static int Lztrans=0;
  46. static int Lzmanag=0;
  47. static int Lskipnocor=0;
  48. static int Lzconv=0;
  49. static int Beenhereb4;
  50. static char Myattn[]={0};
  51. static long startime,endtime;
  52. #if 1
  53. static char *qbf=
  54.  "The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
  55. #else
  56. static char *qbf=
  57.  "≈ ▐┴▌┴╚ └╟┴ ╓╔╠ ┬┘ ├╔╘╥╒╙? Σ┴! ε╧ ╞┴╠╪█╔╫┘╩ ▄╦┌┼═╨╠╤╥ 0123456789\r\n";
  58. #endif
  59.  
  60. extern void get_frame_buffer(void);
  61.  
  62. int zmsndfiles(file_list*);
  63. int zmsndfiles(lst)
  64. file_list *lst;
  65. {
  66.     int rc,maxrc=0;
  67.     file_list *tmpf;
  68.  
  69.     loginf("start %s send%s",
  70.         (emsi_local_protos & ZAP)?"ZedZap":"Zmodem",
  71.         lst?"":" (dummy)");
  72.  
  73.     get_frame_buffer();
  74.  
  75.     if ((rc=initsend())) return abs(rc);
  76.     for (tmpf=lst;tmpf && (maxrc < 2);tmpf=tmpf->next)
  77.     {
  78.         if (tmpf->remote)
  79.         {
  80.             rc=sendfile(tmpf->local,tmpf->remote);
  81.             rc=abs(rc);
  82.             if (rc > maxrc) maxrc=rc;
  83.             if (rc == 0) execute_disposition(tmpf);
  84.         }
  85.         else if (maxrc == 0) execute_disposition(tmpf);
  86.     }
  87.     if (maxrc < 2)
  88.     {
  89.         rc=finsend();
  90.         rc=abs(rc);
  91.     }
  92.     if (rc > maxrc) maxrc=rc;
  93.  
  94.     loginf("zmodem send rc=%d",maxrc);
  95.     return maxrc;
  96. }
  97.  
  98. static int initsend(void)
  99. {
  100.     debug(11,"initsend");
  101.  
  102.     PUTSTR("rz\r");
  103.     stohdr(0L);
  104.     zshhdr(4,ZRQINIT,Txhdr);
  105.     if (getzrxinit())
  106.     {
  107.         loginf("unable to initiate zmodem send");
  108.         return 1;
  109.     }
  110.     return 0;
  111. }
  112.  
  113. static int finsend(void)
  114. {
  115.     int rc;
  116.  
  117.     debug(11,"finsend");
  118.     while (GETCHAR(1) >= 0) /*nothing*/;
  119.     while (1)
  120.     {
  121.         stohdr(0L);
  122.         zshhdr(4,ZFIN,Txhdr);
  123.         if ((rc=zgethdr(Rxhdr,0)) == ZFIN) PUTSTR("OO");
  124.         if ((rc == ZFIN) || (rc == ZCAN) || (rc < 0)) break;
  125.     }
  126.     return (rc != ZFIN);
  127. }
  128.  
  129. static int sendfile(ln,rn)
  130. char *ln,*rn;
  131. {
  132.     int rc=0;
  133.     struct stat st;
  134.     struct flock fl = {
  135.         F_RDLCK,
  136.         0,
  137.         0L,
  138.         0L,
  139.         0
  140.     };
  141.     int bufl;
  142.  
  143.     if (txbuf == NULL) txbuf=xmalloc(MAXBLOCK);
  144.  
  145.     if ((in=fopen(ln,"r")) == NULL)
  146.     {
  147.         logerr("$zmsend cannot open file %s, skipping",ln);
  148.         if (errno == ENOENT) return 0;
  149.         else return 1;
  150.     }
  151.     if (fcntl(fileno(in),F_SETLK,&fl) != 0)
  152.     {
  153.         loginf("$zmsend cannot lock file %s, skipping",ln);
  154.         fclose(in);
  155.         return 1;
  156.     }
  157.     if (stat(ln,&st) != 0)
  158.     {
  159.         loginf("$cannot access \"%s\", skipping",ln);
  160.         fclose(in);
  161.         return 1;
  162.     }
  163.  
  164.     loginf("zmodem send \"%s\" as \"%s\" (%lu bytes)",ln,rn,st.st_size);
  165.     (void)time(&startime);
  166.  
  167.     sprintf(txbuf,"%s %lu %lo %o 0 0 0",
  168.         rn,st.st_size,st.st_mtime,st.st_mode);
  169.     bufl=strlen(txbuf);
  170.     *(strchr(txbuf,' '))='\0'; /*hope no blanks in filename*/
  171.  
  172.     Eofseen = 0;
  173.     rc=zsendfile(txbuf,bufl);
  174.     if (rc == ZSKIP)
  175.     {
  176.         loginf("file %s considered normally sent",ln);
  177.         return 0;
  178.     }
  179.     else if (rc == OK)
  180.     {
  181.         (void)time(&endtime);
  182.         if ((startime=endtime-startime) == 0) startime=1;
  183.         loginf("sent %lu bytes in %ld seconds (%ld cps)",
  184.             st.st_size,startime,st.st_size/startime);
  185.         return 0;
  186.     }
  187.     else return rc;
  188. }
  189.  
  190. /*
  191.  * Get the receiver's init parameters
  192.  */
  193. int getzrxinit(void)
  194. {
  195.     register n;
  196.  
  197.     debug(11,"getzrxinit");
  198.     for (n=10; --n>=0; ) {
  199.         
  200.         switch (zgethdr(Rxhdr, 1)) {
  201.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  202.             stohdr(Rxpos);
  203.             zshhdr(4, ZACK, Txhdr);
  204.             continue;
  205.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  206.             stohdr(0L);
  207.             zshhdr(4, ZRQINIT, Txhdr);
  208.             continue;
  209.         case ZRINIT:
  210.             Rxflags = 0377 & Rxhdr[ZF0];
  211.             Usevhdrs = Rxhdr[ZF1] & CANVHDR;
  212.             Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  213.             Zctlesc |= Rxflags & TESCCTL;
  214.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  215.             if ( !(Rxflags & CANFDX))
  216.                 Txwindow = 0;
  217.             debug(11,"Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  218.  
  219.             /* Override to force shorter frame length */
  220.             if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  221.                 Rxbuflen = Tframlen;
  222.             if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
  223.                 Rxbuflen = Tframlen;
  224.             debug(11,"Rxbuflen=%d", Rxbuflen);
  225.  
  226.             /* Set initial subpacket length */
  227.             if (blklen < 1024) {    /* Command line override? */
  228.                 blklen = 1024;
  229.             }
  230.             if (Rxbuflen && blklen>Rxbuflen)
  231.                 blklen = Rxbuflen;
  232.             if (blkopt && blklen > blkopt)
  233.                 blklen = blkopt;
  234.             debug(11,"Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  235.             debug(11,"Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  236.  
  237.  
  238.             if (Lztrans == ZTRLE && (Rxflags & CANRLE))
  239.                 Txfcs32 = 2;
  240.             else
  241.                 Lztrans = 0;
  242.  
  243.             return (sendzsinit());
  244.         case ZCAN:
  245.         case ERROR:
  246.             return ERROR;
  247.         case HANGUP:
  248.             return HANGUP;
  249.         case TIMEOUT:
  250.             stohdr(0L);
  251.             zshhdr(4, ZRQINIT, Txhdr);
  252.             continue;
  253.         case ZRQINIT:
  254.             if (Rxhdr[ZF0] == ZCOMMAND)
  255.                 continue;
  256.         default:
  257.             zshhdr(4, ZNAK, Txhdr);
  258.             continue;
  259.         }
  260.     }
  261.     return ERROR;
  262. }
  263.  
  264. /* Send send-init information */
  265. int sendzsinit(void)
  266. {
  267.     register c;
  268.  
  269.     debug(11,"sendzsinit");
  270.     if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
  271.         return OK;
  272.     errors = 0;
  273.     for (;;) {
  274.         stohdr(0L);
  275.         if (Zctlesc) {
  276.             Txhdr[ZF0] |= TESCCTL; zshhdr(4, ZSINIT, Txhdr);
  277.         }
  278.         else
  279.             zsbhdr(4, ZSINIT, Txhdr);
  280.         zsdata(Myattn, ZATTNLEN, ZCRCW);
  281.         c = zgethdr(Rxhdr, 1);
  282.         switch (c) {
  283.         case ERROR:
  284.         case ZCAN:
  285.             return ERROR;
  286.         case HANGUP:
  287.             return HANGUP;
  288.         case ZACK:
  289.             return OK;
  290.         default:
  291.             if (++errors > 19)
  292.                 return ERROR;
  293.             continue;
  294.         }
  295.     }
  296. }
  297.  
  298. /* Fill buffer with blklen chars */
  299. int zfilbuf(void)
  300. {
  301.     int n;
  302.  
  303.     debug(11,"zfilbuf (%d)",blklen);
  304.     n = fread(txbuf, 1, blklen, in);
  305.     if (n < blklen)
  306.         Eofseen = 1;
  307.     debug(11,"zfilbuf return %d",n);
  308.     return n;
  309. }
  310.  
  311. /* Send file name and related info */
  312. int zsendfile(buf, blen)
  313. char *buf;
  314. int blen;
  315. {
  316.     register c;
  317.     register long crc=-1L;
  318.     long lastcrcrq = -1;
  319.  
  320.     debug(11,"zsendfile %s (%d)",buf,blen);
  321.     for (errors=0; ++errors<11;) {
  322.         Txhdr[ZF0] = Lzconv;    /* file conversion request */
  323.         Txhdr[ZF1] = Lzmanag;    /* file management request */
  324.         if (Lskipnocor)
  325.             Txhdr[ZF1] |= ZMSKNOLOC;
  326.         Txhdr[ZF2] = Lztrans;    /* file transport request */
  327.         Txhdr[ZF3] = 0;
  328.         zsbhdr(4, ZFILE, Txhdr);
  329.         zsdata(buf, blen, ZCRCW);
  330. again:
  331.         c = zgethdr(Rxhdr, 1);
  332.         switch (c) {
  333.         case ZRINIT:
  334.             while ((c = GETCHAR(5)) > 0)
  335.                 if (c == ZPAD) {
  336.                     goto again;
  337.                 }
  338.             continue;
  339.         case ZCAN:
  340.         case ERROR:
  341.         case HANGUP:
  342.         case TIMEOUT:
  343.         case ZABORT:
  344.         case ZFIN:
  345.             loginf("Got %s on pathname", frametypes[c+FTOFFSET]);
  346.             return c;
  347.         default:
  348.             loginf("Got %d frame type on pathname", c);
  349.             continue;
  350.         case ZNAK:
  351.             continue;
  352.         case ZCRC:
  353.             if (Rxpos != lastcrcrq) {
  354.                 lastcrcrq = Rxpos;
  355.                 crc = 0xFFFFFFFFL;
  356.                 fseek(in, 0L, 0);
  357.                 while (((c = getc(in)) != EOF) && --lastcrcrq)
  358.                     crc = updcrc32(c, crc);
  359.                 crc = ~crc;
  360.                 clearerr(in);    /* Clear possible EOF */
  361.                 lastcrcrq = Rxpos;
  362.             }
  363.             stohdr(crc);
  364.             zsbhdr(4, ZCRC, Txhdr);
  365.             goto again;
  366.         case ZFERR:
  367.         case ZSKIP:
  368.             loginf("File skipped by receiver request");
  369.             fclose(in); return c;
  370.         case ZRPOS:
  371.             /*
  372.              * Suppress zcrcw request otherwise triggered by
  373.              * lastyunc==bytcnt
  374.              */
  375.             if (fseek(in, Rxpos, 0))
  376.                 return ERROR;
  377.             Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1;
  378.             return zsendfdata();
  379.         }
  380.     }
  381.     fclose(in); return ERROR;
  382. }
  383.  
  384. /* Send the data in the file */
  385. int zsendfdata(void)
  386. {
  387.     register c=0, e, n;
  388.     register newcnt;
  389.     register long tcount = 0;
  390.     int junkcount;        /* Counts garbage chars received by TX */
  391.     static int tleft = 6;    /* Counter for test mode */
  392.     int maxblklen,goodblks=0,goodneeded=8;
  393.  
  394.     debug(11,"zsendfdata");
  395.  
  396.     if (emsi_local_protos & ZAP) maxblklen=MAXBLOCK;
  397.     else maxblklen=1024;
  398.     if (maxblklen > Rxbuflen) maxblklen=Rxbuflen;
  399.  
  400.     junkcount = 0;
  401.     Beenhereb4 = 0;
  402. somemore:
  403.  
  404.     if (0) {
  405.  
  406. waitack:
  407.         junkcount = 0;
  408.         c = getinsync(0);
  409. gotack:
  410.         switch (c) {
  411.         default:
  412.         case ZCAN:
  413.             fclose(in);
  414.             return ERROR;
  415.         case ZSKIP:
  416.             fclose(in);
  417.             return c;
  418.         case ZACK:
  419.         case ZRPOS:
  420.             break;
  421.         case ZRINIT:
  422.             fclose(in);
  423.             return OK;
  424.         }
  425.         /*
  426.          * If the reverse channel can be tested for data,
  427.          *  this logic may be used to detect error packets
  428.          *  sent by the receiver, in place of setjmp/longjmp
  429.          *  rdchk(fd) returns non 0 if a character is available
  430.          */
  431.         TTYWAIT(0);
  432.         if ((c=GETCHAR(1)) == EMPTY)
  433.         {
  434.             TTYWAIT(1);
  435.         }
  436.         else if (c < 0)
  437.         {
  438.             return c;
  439.         }
  440.         else switch (c)
  441.         {
  442.         case CAN:
  443.         case ZPAD:
  444.             TTYWAIT(1);
  445.             c = getinsync(1);
  446.             goto gotack;
  447.         case DC3:        /* Wait a while for an XON */
  448.         case DC3|0200:
  449.             TTYWAIT(1);
  450.             GETCHAR(10);
  451.         }
  452.  
  453.     }
  454.  
  455.     newcnt = Rxbuflen;
  456.     Txwcnt = 0;
  457.     stohdr(Txpos);
  458.     zsbhdr(4, ZDATA, Txhdr);
  459.  
  460.     /*
  461.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  462.      *  many times.  Each time the signal should be caught, causing the
  463.      *  file to be started over from the beginning.
  464.      */
  465.     if (Test) {
  466.         if ( --tleft)
  467.             while (tcount < 20000) {
  468.                 printf(qbf); fflush(stdout);
  469.                 tcount += strlen(qbf);
  470.                 TTYWAIT(0);
  471.                 if ((c=GETCHAR(1)) == EMPTY)
  472.                 {
  473.                     TTYWAIT(1); break;
  474.                 }
  475.                 else if (c < 0)
  476.                 {
  477.                     return c;
  478.                 }
  479.                 else switch (c)
  480.                 {
  481.                 case CAN:
  482.                 case ZPAD:
  483.                     TTYWAIT(1);
  484.                     goto waitack;
  485.                 case DC3:    /* Wait for XON */
  486.                 case DC3|0200:
  487.                     TTYWAIT(1);
  488.                     GETCHAR(10);
  489.                 }
  490.             }
  491.         sleep(3); fflush(stdout);
  492.         printf("\nsz: Tcount = %ld\n", tcount);
  493.         if (tleft) {
  494.             printf("ERROR: Interrupts Not Caught\n");
  495.             exit(1);
  496.         }
  497.         exit(0);
  498.     }
  499.  
  500.     do {
  501.         n = zfilbuf();
  502.         if (Eofseen)
  503.             e = ZCRCE;
  504.         else if (junkcount > 3)
  505.             e = ZCRCW;
  506.         else if (bytcnt == Lastsync)
  507.             e = ZCRCW;
  508.         else if (Rxbuflen && (newcnt -= n) <= 0)
  509.             e = ZCRCW;
  510.         else if (Txwindow && (Txwcnt += n) >= Txwspac) {
  511.             Txwcnt = 0;  e = ZCRCQ;
  512.         } else
  513.             e = ZCRCG;
  514.         debug(11,"%7ld ZMODEM%s    ",
  515.               Txpos, Crc32t?" CRC-32":"");
  516.         zsdata(txbuf, n, e);
  517.         bytcnt = Txpos += n;
  518.  
  519.         if ((blklen < maxblklen) && (++goodblks > goodneeded))
  520.         {
  521.             blklen = ((blklen << 1) < maxblklen) ? blklen << 1 :
  522.                 maxblklen;
  523.             goodblks = 0;
  524.         }
  525.  
  526.         if (e == ZCRCW)
  527.             goto waitack;
  528.         /*
  529.          * If the reverse channel can be tested for data,
  530.          *  this logic may be used to detect error packets
  531.          *  sent by the receiver, in place of setjmp/longjmp
  532.          *  rdchk(fd) returns non 0 if a character is available
  533.          */
  534.         TTYWAIT(0);
  535.         if ((c=GETCHAR(1)) == EMPTY)
  536.         {
  537.             TTYWAIT(1);
  538.         }
  539.         else if (c < 0)
  540.         {
  541.             return c;
  542.         }
  543.         else switch (c)
  544.         {
  545.         case CAN:
  546.         case ZPAD:
  547.             TTYWAIT(1);
  548.             c = getinsync(1);
  549.             if (c == ZACK)
  550.                 break;
  551.             /* zcrce - dinna wanna starta ping-pong game */
  552.             zsdata(txbuf, 0, ZCRCE);
  553.             goto gotack;
  554.         case DC3:        /* Wait a while for an XON */
  555.         case DC3|0200:
  556.             TTYWAIT(1);
  557.             GETCHAR(10);
  558.         default:
  559.             ++junkcount;
  560.         }
  561.         if (Txwindow) {
  562.             while ((tcount = (Txpos - Lrxpos)) >= Txwindow) {
  563.                 debug(11,"%ld window >= %u", tcount, Txwindow);
  564.                 if (e != ZCRCQ)
  565.                     zsdata(txbuf, 0, e = ZCRCQ);
  566.                 c = getinsync(1);
  567.                 if (c != ZACK) {
  568.                     zsdata(txbuf, 0, ZCRCE);
  569.                     goto gotack;
  570.                 }
  571.             }
  572.             debug(11,"window = %ld", tcount);
  573.         }
  574.     } while (!Eofseen);
  575.  
  576.     for (;;) {
  577.         stohdr(Txpos);
  578.         zsbhdr(4, ZEOF, Txhdr);
  579.         switch (getinsync(0)) {
  580.         case ZACK:
  581.             continue;
  582.         case ZRPOS:
  583.             goto somemore;
  584.         case ZRINIT:
  585.             fclose(in);
  586.             return OK;
  587.         case ZSKIP:
  588.             fclose(in);
  589.             loginf("File skipped by receiver request");
  590.             return c;
  591.         default:
  592.             debug(11,"Got %d trying to send end of file", c);
  593.             fclose(in);
  594.             return ERROR;
  595.         }
  596.     }
  597. }
  598.  
  599. /*
  600.  * Respond to receiver's complaint, get back in sync with receiver
  601.  */
  602. int getinsync(flag)
  603. int flag;
  604. {
  605.     register c;
  606.  
  607.     debug(11,"getinsync");
  608.     for (;;) {
  609.         c = zgethdr(Rxhdr, 0);
  610.         switch (c) {
  611.         case HANGUP:
  612.             return HANGUP;
  613.         case ZCAN:
  614.         case ZABORT:
  615.         case ZFIN:
  616.         case ERROR:
  617.         case TIMEOUT:
  618.             loginf("Got %s sending data", frametypes[c+FTOFFSET]);
  619.             return ERROR;
  620.         case ZRPOS:
  621.             /* ************************************* */
  622.             /*  If sending to a buffered modem, you  */
  623.             /*   might send a break at this point to */
  624.             /*   dump the modem's buffer.         */
  625.             clearerr(in);    /* In case file EOF seen */
  626.             if (fseek(in, Rxpos, 0))
  627.                 return ERROR;
  628.             Eofseen = 0;
  629.             bytcnt = Lrxpos = Txpos = Rxpos;
  630.             if (Lastsync == Rxpos) {
  631.                 if (++Beenhereb4 > 12) {
  632.                     loginf("Can't send block");
  633.                     return ERROR;
  634.                 }
  635.                 if (Beenhereb4 > 4)
  636.                     if (blklen > 32)
  637.                         blklen /= 2;
  638.             }
  639.             Lastsync = Rxpos;
  640.             return c;
  641.         case ZACK:
  642.             Lrxpos = Rxpos;
  643.             if (flag || Txpos == Rxpos)
  644.                 return ZACK;
  645.             continue;
  646.         case ZRINIT:
  647.             return c;
  648.         case ZSKIP:
  649.             loginf("File skipped by receiver request");
  650.             return c;
  651.         default:
  652.             zsbhdr(4, ZNAK, Txhdr);
  653.             continue;
  654.         }
  655.     }
  656. }
  657.